﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sharkbite.Irc;
using System.Windows.Forms;

namespace kopan_irc
{
    class IRC
    {
        private Connection connection;
        formTororo toroForm;
        string channelName = "#ddokorea";
        string nickName;
        string server = "irc.holywar.net";

        void SetChannelName(string name)
        {
            channelName = name;
        }

        void SetNickName(string name)
        {
            nickName = name;
        }

        public IRC(formTororo value, string nick, string channel)
        {
            toroForm = value;
            nickName = nick;
            channelName = channel;
        }

        void RegisterEvent()
        {
            //OnRegister tells us that we have successfully established a connection with
            //the server. Once this is established we can join channels, check for people
            //online, or whatever.
            connection.Listener.OnRegistered += new RegisteredEventHandler(OnRegistered);
            //Listen for any messages sent to the channel
            connection.Listener.OnPublic += new PublicMessageEventHandler(OnPublic);

            //Listen for bot commands sent as private messages
            connection.Listener.OnPrivate += new PrivateMessageEventHandler(OnPrivate);
            //Listen for notification that an error has ocurred
            connection.Listener.OnError += new ErrorMessageEventHandler(OnError);

            //Listen for notification that we are no longer connected.
            connection.Listener.OnDisconnected += new DisconnectedEventHandler(OnDisconnected);

            connection.Listener.OnInfo += new InfoEventHandler(OnInfo);
            connection.Listener.OnMotd += new MotdEventHandler(OnMotd);
            connection.Listener.OnNick += new NickEventHandler(OnChangeNick);
            connection.Listener.OnNickError += new NickErrorEventHandler(OnChangeNickError);
            connection.Listener.OnNames += new NamesEventHandler(OnUserList);
            connection.Listener.OnJoin += new JoinEventHandler(OnSomeOneJoin);
            connection.Listener.OnQuit += new QuitEventHandler(OnSomeOneQuit);
            connection.Listener.OnPing += new PingEventHandler(OnPing);
        }

        private void CreateConnection()
        {
            //The bot's nick on IRC
            string nick = nickName;
            //Fire up the Ident server for those IRC networks
            //silly enough to use it.
            Identd.Start(nick);
            SetNickName(nick);

            //A ConnectionArgs contains all the info we need to establish
            //our connection with the IRC server and register our bot.
            //This line uses the simplfied contructor and the default values.
            //With this constructor the Nick, Real Name, and User name are
            //all set to the same value. It will use the default port of 6667 and no server
            //password.
            ConnectionArgs cargs = new ConnectionArgs(nick, server);
            //When creating a Connection two additional protocols may be
            //enabled: CTCP and DCC. In this example we will disable them
            //both.
            connection = new Connection(cargs, false, false);

            //NOTE
            //We could have created multiple Connections to different IRC servers
            //and each would process messages simultaneously and independently.
            //There is no fixed limit on how many Connection can be opened at one time but
            //it is important to realize that each runs in its own Thread. Also,separate event
            //handlers are required for each connection, i.e. the
            //same OnRegistered () handler cannot be used for different connection
            //instances.
        }

        public void end()
        {
            if( Identd.IsRunning() )
                Identd.Stop();

            if(connection.Connected)
                connection.Disconnect("Bye");

            toroForm.RemoveAllUserList();
        }
        public void start()
        {
            if (connection != null)
            {
                if (connection.Connected)
                {
                    end();
                    //toroForm.AddToText("(Info) 이미 접속중 입니다.");
                    //return;
                }
            }
            
            if( Identd.IsRunning())
            {
                Identd.Stop();
            }

            CreateConnection();
            RegisterEvent();
            //Notice that by having the actual connect call here
            //the constructor can add the necessary listeners before
            //the connection process begins. If listeners are added
            //after connecting they may miss certain events. the OnRegistered()
            //event will certainly be missed.

            try
            {
                //Calling Connect() will cause the Connection object to open a
                //socket to the IRC server and to spawn its own thread. In this
                //separate thread it will listen for messages and send them to the
                //Listener for processing.
                connection.Connect();

                toroForm.AddToText("Connecting..." + server);
                //The main thread ends here but the Connection's thread is still alive.
                //We are now in a passive mode waiting for events to arrive.
            }
            catch (Exception e)
            {
                toroForm.AddToText("Error during connection process.");
                toroForm.AddToText(e.ToString());
                Identd.Stop();
            }
        }

        public void OnRegistered()
        {
            //We have to catch errors in our delegates because Thresher purposefully
            //does not handle them for us. Exceptions will cause the library to exit if they are not
            //caught.
            try
            {
                //Don't need this anymore in this example but this can be left running
                //if you want.
                Identd.Stop();

                //The connection is ready so lets join a channel.
                //We can join any number of channels simultaneously but
                //one will do for now.
                //All commands are sent to IRC using the Sender object
                //from the Connection.
                JoinChannel(channelName);
            }
            catch (Exception e)
            {
                toroForm.AddToText("Error in OnRegistered(): " + e);
            }
        }

        public void ChangeNick(string name)
        {
            
            if (name.Length > 1)
            {
               connection.Sender.Nick(name);
            }
            else
            {
                toroForm.AddToText("(Info)Nickname needs over then 1 String");
            }
        }

        public void JoinChannel(string name)
        {
            SetChannelName(name);
            connection.Sender.Join(name);
            toroForm.AddToText("Join " + channelName);
        }

        public void SendPublicMessage(string message)
        {
            if(message == "/list")
            {
                connection.Sender.Names(channelName);
            }
            else
            {
                connection.Sender.PublicMessage(channelName, message);
                toroForm.AddToText("[" + connection.Name + "]" + " " + message);
            }
        }

        public void OnPublic(UserInfo user, string channel, string message)
        {
            //Echo back any public messages
            //connection.Sender.PublicMessage(channel, user.Nick + " said, " + message);
            if (channelName == channel)
            {
                toroForm.AddToText("[" + user.Nick + "]" + " " + message);
            }
        }

        public void OnPrivate(UserInfo user, string message)
        {
            //Quit IRC if someone sends us a 'die' message
            toroForm.AddToText("(귓말)" + "[" + user.Nick + "]" + " : " + message);
        }

        public void OnError(ReplyCode code, string message)
        {
            if (code == ReplyCode.ERR_NOMOTD)
            {
                toroForm.AddToText("Channel joined");
            }
            else if (code == ReplyCode.ConnectionFailed)
            {
                end();
            }
            else
            {
                //All anticipated errors have a numeric code. The custom Thresher ones start at 1000 and
                //can be found in the ErrorCodes class. All the others are determined by the IRC spec
                //and can be found in RFC2812Codes.
                toroForm.AddToText("error type " + code + " / " + message + " has occurred.");
            }
        }

        public void OnDisconnected()
        {
            //If this disconnection was involutary then you should have received an error
            //message ( from OnError() ) before this was called.
            toroForm.AddToText("Connection to the server has been closed.");
            start();
        }

        public void OnInfo(string message, bool last)
        {
            toroForm.AddToText("(Info) " + message);
        }

        public void OnMotd(string message, bool last)
        {
            toroForm.AddToText("(Motd) " + message);
        }

        public void OnChangeNick(UserInfo user, string newNick)
        {
            toroForm.AddToText("[" + user.Nick + "] change to " + "[" + newNick + "]");
            SetNickName(newNick);
        }

        public void OnChangeNickError(string badNick, string reason)
        {
            toroForm.AddToText("(Info) Error Change Nick [" + badNick + "] reason : " + reason);
        }

        public void OnUserList(string channel, string[] nicks, bool last)
        {
            
            if(last == false)
            {
                foreach (string nick in nicks)
                {
                    toroForm.AddToText("(Info) " + nick + " is Online");
                    toroForm.AddToUserList(nick);
                }
            }
        }

        public void OnSomeOneJoin(UserInfo user, string channel)
        {
            if (channelName == channel)
            {
                toroForm.AddToText("(Info) " + user.Nick + " is Join");
                toroForm.AddToUserList(user.Nick);
            }
        }

        public void OnSomeOneQuit(UserInfo user, string reason)
        {
            toroForm.AddToText("(Info) " + user.Nick + reason);
            toroForm.RemoveToUserList(user.Nick);
        }

        void OnPing(string message)
        {
            connection.Sender.PublicMessage(channelName, message);
        }
    }
}
